iT邦幫忙

2023 iThome 鐵人賽

DAY 24
0
Modern Web

職缺資訊平台—Jobscanner系列 第 24

[開發] 資料彙整 - 觀察

  • 分享至 

  • xImage
  •  

職缺

進入各求職平台,搜尋前端關鍵字為例,觀察資料來源以及類型 (使用平台預設條件或排序,不另做設定)

104

網頁:https://www.104.com.tw/jobs/search/?keyword=前端&order=1&jobsource=2018indexpoc&ro=0
預設以符合度排序,屬於 Server Side Render,可使用 Axios + cheerio

各項職缺提供的資訊:
https://ithelp.ithome.com.tw/upload/images/20231009/20128122CvziczigbL.png

  • 更新狀態 (更新日期)
  • 職稱
  • 公司名稱
  • 公司產業
  • 工作地點 (縣市+區)
  • 工作經歷
  • 學歷要求
  • 職缺描述
  • 其他標籤 (薪資、員工數、遠端、最近捷運站...等)
  • 應徵人數

yourator

網頁:https://www.yourator.co/jobs?term[]=前端
預設以相關程度排序,有 API,可使用 Axios

各項職缺提供的資訊:
https://ithelp.ithome.com.tw/upload/images/20231009/20128122npx0oNe4ev.png

  • 公司圖片
  • 職稱
  • 公司 Logo
  • 公司名稱
  • 工作地點 (縣市)
  • 更新狀態 (一週內更新/兩週內更新/一個月前更新/...)
  • 薪資範圍
  • 其他標籤 (ReactJS/Next.js/webGL/....等)

API:https://www.yourator.co/api/v4/jobs?page=1&term[]=前端


CakeResume

網頁:https://www.cakeresume.com/jobs/前端
預設以熱門程度排序,屬於 Server Side Render,可使用 Axios + cheerio

各項職缺提供的資訊:
https://ithelp.ithome.com.tw/upload/images/20231009/20128122Fr0dQ9Bj6e.png

  • 公司 Logo
  • 職稱
  • 公司名稱
  • 職缺描述
  • 需求人數
  • 工作地點 (縣市+地區)
  • 薪資範圍
  • 工作年資
  • 管理責任
  • 其他標籤 (Vue.js/Node.js/CSS/...等)
  • 雇主活躍度
  • 瀏覽次數

整理

項目 104 數字網 yourator CakeResume
職稱 v v v
公司名稱 v v v
公司 Logo v v
公司產業 v
職缺描述 v v
工作地點 v v v
工作經歷 v v
薪資範圍 - v v
其他標籤 v v v
學歷要求 v
需求人數 v
管理責任 v
瀏覽次數 v
更新狀態 v v
雇主活躍度 v

JobScanner 需要的資訊,包含:職稱、公司名稱、Logo、職缺描述、工作地點、薪資、其他標籤、職缺連結 (104:無 Logo 以灰底圖替代;薪資資訊從其他標籤取得)

{
    "name": "前端工程師 (Front-end Engineer)",
    "companyName": "xxx有限公司",
    "companyLogo": "https://xxx/xxx.png",
    "description": "xxxxx",
    "location": "xxxx",
    "salary": "NT$ 50,000 - 65,000 (月薪)",
    "tags": ["JavaScript", "ReactJS", "Git", "Redux", "前端工程師"],
    "url": "https://www.xxxxx",
}

分頁

觀察求職平台是如何載入更多職缺

104

進入網頁:https://www.104.com.tw/jobs/search/?keyword=前端&order=1&jobsource=2018indexpoc&ro=0

向下捲動會自動載入更多職缺

網址會被替換成:https://www.104.com.tw/jobs/search/?ro=0&kwop=7&keyword=前端&expansionType=area,spec,com,job,wf,wktm&order=15&asc=0&page=2&mode=s&jobsource=2018indexpoc&langFlag=0&langStatus=0&recommendJob=1&hotJob=1

*省略部分 query string 結果大致相同,例如:
https://www.104.com.tw/jobs/search/?ro=0&kwop=7&keyword=前端&expansionType=area,spec,com,job,wf,wktm&order=15&asc=0&page=2&mode=s&jobsource=2018indexpoc&langFlag=0&langStatus=0&recommendJob=1&hotJob=1

改為https://www.104.com.tw/jobs/search/?keyword=前端&order=1&jobsource=2018indexpoc&ro=0&page=2


yourator

進入網頁:https://www.yourator.co/jobs?term[]=%E5%89%8D%E7%AB%AF

向下捲動會自動載入更多職缺

API 會 call https://www.yourator.co/api/v4/jobs?page=2&term[]=前端


CakeResume

進入網頁:https://www.cakeresume.com/jobs/前端

捲至底部時,會有 Pagination 可以做切換,點擊第二頁後

網址會更改為:https://www.cakeresume.com/jobs/前端?page=2

三個求職平台都是改變 query String 中 page 的值


本機測試

以關鍵字 前端,取得 104 求職平台前三頁的資料為例:

先確認 robots.txt 內容
https://ithelp.ithome.com.tw/upload/images/20231009/20128122P1n83QpjJO.png

使用 Axios + cheerio,透過 class、attribute 選取元素,取得資料內容,並存入 json

const fs = require("fs"),
      axios = require("axios"),
      cheerio = require("cheerio");

let jobList = [],
	page = 1,
    baseUrl = `https://www.104.com.tw/jobs/search/`,
    keyword = '前端';

const fetchJob = async(keyword, page = 1) => {
	console.log(`Fetch page data --- Page ${page}`);

	let url =`${baseUrl}?order=1&jobsource=2018indexpoc&ro=0&keyword=${keyword}&page=${page}`
	let data = await axios.get(url);
	let $ = cheerio.load(data.data);

	$('.job-list-item').each(function () {
		let $this = $(this);
		let name = $this.find('.b-tit a.js-job-link').text(),
            companyName = $this.find('.b-list-inline li:nth-child(2) > a').text(),
            description = $this.find('.job-list-item__info').text(),
            location = $this.find('.job-list-intro > li:first-child').text(),
            url = $this.find('.b-tit a.js-job-link').attr("href"),
            salary = '',
            tags = [];
		$this.find('.job-list-tag a').each(function () {
			let $tag = $(this);
			if ($tag.text().includes('薪')) salary = $tag.text();
			tags.push($tag.text());
		});
		url = url && url.replace(/^\/\//, '');
		jobList.push({name, companyName, companyLogo: '', description, location, salary, tags, url });
	});
}

const writeFile = (fileName, data) => {
	fs.writeFile(fileName, data, "utf8", function (err) {
		if (err) {
			console.log("Something error while writing JSON Object to File.");
			return console.log(err);
		}
		console.log("JSON file has been saved.");
	});
}

const init = async() => {
	do {
		await fetchJob(keyword, page);
		page += 1;
	} while(page <= 3)

  const result = jobList.filter(item => item.name.includes(keyword));
  writeFile('104.json', JSON.stringify(result));
}

init();


  • 可能會夾雜一些非前端的職缺,使用 filter 以 keyword 過濾職缺名稱
  • 若其他標籤中出現 關鍵字,作為 salary 資料

上一篇
[開發] React 從 0 到 0.1 (7)
下一篇
[開發] 資料彙整 - 乾淨的源頭
系列文
職缺資訊平台—Jobscanner31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言